/**
 * 
 */
package view.impl;

import java.io.FileNotFoundException;

import model.EMenuState;
import model.IinGame;
import model.ModelFactory;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;

import sharedGameLogic.enums.BattleDistance;
import sharedGameLogic.enums.GameStatus;
import util.ResLoc;
import view.impl.ingame.EffectDispatch;
import view.impl.ingame.Fighter;
import view.impl.ingame.GameHUD;
import view.impl.ingame.GameStage;
import view.impl.ingame.StageLoadException;
import view.impl.ingame.StageLoader;
import view.impl.ingame.Fighter.Player;
import view.impl.ingame.animation.AnimationLoadException;

/**
 * A class that implements the interface IViewState. Defines a state that displays
 * the in-game screen. Will draw the two opposing characters, display their animations,
 * render associated data (such as health, energy, name) and the action menu.
 * 
 * @author Julian
 */
class InGameState implements IViewState {
	private static final boolean SOUND_ENABLED = true;
	
	private Sound loseSound = null;
	private boolean soundPlayed = false;
	
	//private static InGameState INSTANCE = new InGameState();
	private Fighter player1;
	private Fighter player2;
	
	private GameStage stage = null;
	private GameHUD hud = null;
	
	private int windowWidth = 800;
	private int windowHeight = 600;
	
	/**
	 * Private constructor, as defined in Singleton-pattern.
	 */
	InGameState() throws RenderException {
		init();
		
		if(SOUND_ENABLED) {
			try {
				loseSound = new Sound("data/sound/lose.ogg");
			} catch (SlickException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
//	/**
//	 * @return A singleton instance of InGameState.
//	 */
//	static InGameState getInstance() {
//		return INSTANCE;
//	}
	
	private void init() throws RenderException {
		IinGame model = ModelFactory.getViewModel().getInGameState();
		
		try {
			stage = StageLoader.loadStage(ResLoc.getResource("InGame.stages") + "/beach");
		} catch (StageLoadException e) {
			throw new RenderException("Unable to load stage \"beach\".", e);
		} catch (FileNotFoundException e) {
			throw new RenderException("Unable to load stage \"beach\".", e);
		}

		player1 = stage.getFighter(Player.PLAYER1);
		player2 = stage.getFighter(Player.PLAYER2);
		try {
			player1.loadCharacter(ResLoc.getResource("CharSelect.charFolder") + "/anna");
			player2.loadCharacter(ResLoc.getResource("CharSelect.charFolder") + "/anna");
		} catch (AnimationLoadException e) {
			throw new RenderException("Unable to load characters for in game screen.", e);
		} catch (FileNotFoundException e) {
			throw new RenderException("Unable to load characters for in game screen.", e);
		}

		try {
			hud = new GameHUD(player1, model.getPlayerOneNick(), model.getPlayerOneCharacterName(), 
							  player2, model.getPlayerTwoNick(), model.getPlayerTwoCharacterName());
		} catch (SlickException e) {
			throw new RenderException("Unable to create in game head-up-display.", e);
		} catch (FileNotFoundException e) {
			throw new RenderException("Unable to create in game head-up-display.", e);
		}
	}

	/* (non-Javadoc)
	 * @see client.view.IViewState#changeResolution(int, int)
	 */
	@Override
	public void changeResolution(int targetWidth, int targetHeight) {
		windowWidth = targetWidth;
		windowHeight = targetHeight;
	}

	/* (non-Javadoc)
	 * @see client.view.IViewState#render()
	 */
	@Override
	public void render(Graphics g) {
		EffectDispatch ed = EffectDispatch.getInstance();
		float scaleX = (float)windowWidth / 800f;
		
		IinGame model = ModelFactory.getViewModel().getInGameState();
		
		if(model.getDistance() == BattleDistance.CLOSE_COMBAT) { // Fix proper values.
			player1.setPosX((int) (330 * scaleX));
			player2.setPosX((int) (470 * scaleX));
		} else {
			player1.setPosX((int) (230 * scaleX));
			player2.setPosX((int) (570 * scaleX));
		}
		
		// Set animations.
		if(model.hasChanged() && model.getPlayerOneAction() != null &&
								 model.getPlayerTwoAction() != null ) {
			player1.setAnimation(model.getPlayerOneAction().toString(), model.isPlayerOneActionSuccessful());
			player2.setAnimation(model.getPlayerTwoAction().toString(), model.isPlayerTwoActionSuccessful());
		}
		
		// Check if game is finished and set to winning/losing animation.
		if(!player1.isPlayingAction() && !player2.isPlayingAction() &&
		   model.getGameStatus() != GameStatus.FIGHT_GOING_ON) {
			if(model.getGameStatus() == GameStatus.DRAW) {
				player1.setAnimation("draw", false);
				player2.setAnimation("draw", false);
				
				if(SOUND_ENABLED && !soundPlayed) {		// A quick background music implementation for the presentation.
					loseSound.play();					// Not by any means requirement for the project.
					soundPlayed = true;
				}
			} else if(model.getGameStatus() == GameStatus.PLAYER_ONE_WON){
				player1.setAnimation("win", false);
				player2.setAnimation("lose", false);
				
				if(SOUND_ENABLED && !soundPlayed) {		// A quick background music implementation for the presentation.
					loseSound.play();					// Not by any means requirement for the project.
					soundPlayed = true;
				}
			} else if(model.getGameStatus() == GameStatus.PLAYER_TWO_WON) {
				player1.setAnimation("lose", false);
				player2.setAnimation("win", false);
				
				if(SOUND_ENABLED && !soundPlayed) {		// A quick background music implementation for the presentation.
					loseSound.play();					// Not by any means requirement for the project.
					soundPlayed = true;
				}
			}
			
			
		}
		
		stage.draw(ed, g, windowWidth, windowHeight);
		ed.draw(ModelFactory.getViewModel().getDelta(), player1, player2);
		hud.draw(g, windowWidth, windowHeight);
	}
	
	@Override
	public EMenuState getEMenuTyoe() {
		return EMenuState.IN_GAME;
	}
}